home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Very Best of Atari Inside
/
The Very Best of Atari Inside 1.iso
/
mint
/
mntlib43
/
mntlib
/
malloc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-09-15
|
5KB
|
218 lines
/* from the TOS GCC library */
/* malloc, free, realloc: dynamic memory allocation */
/* ERS: added mlalloc, relalloc, etc. for 16 bit compilers. Changed
argument of malloc, etc., to size_t (per ANSI draft). */
/* 5/2/92 sb -- modified for Heat-n-Serve C to accomodate its 16-bit size_t */
/* 5/5/92 sb -- split off realloc() & calloc() to reduce library drag */
#include <compiler.h>
#include <stddef.h> /* for size_t */
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include "lib.h"
extern long _stksize;
void *_malloc __PROTO((unsigned long));
/* minimum chunk to ask OS for */
static size_t MINHUNK = 4096L; /* default */
static size_t MAXHUNK = 32*1024L; /* max. default */
/* CAUTION: use _mallocChunkSize() to tailor to your environment,
do not make the default too large, as the compiler
gets screwed on a 1M machine otherwise (stack/heap clash)
*/
/* linked list of free blocks struct defined in lib.h */
struct mem_chunk _mchunk_free_list = { VAL_FREE, NULL, 0L };
/* flag to control zero'ing of malloc'ed chunks */
static int _ZeroMallocs = 0;
__EXTERN void _bzero __PROTO((void *, unsigned long));
#ifdef __GNUC__
asm(".stabs \"_malloc\",5,0,0,__malloc"); /* dept of clean tricks */
#endif
void * _malloc(n)
unsigned long n;
{
struct mem_chunk *p, *q;
long sz;
extern void *_heapbase;
extern short _split_mem;
/* add a mem_chunk to required size and round up */
n = n + sizeof(struct mem_chunk);
n = (7 + n) & ~7;
/* look for first block big enough in free list */
p = &_mchunk_free_list;
q = _mchunk_free_list.next;
while ((q != NULL) && (q->size < n))
{
p = q;
q = q->next;
}
/* if not enough memory, get more from the system */
if (q == NULL)
{
if (((!_split_mem) && (_heapbase != NULL)) || (n > MINHUNK))
sz = n;
else {
sz = MINHUNK;
if (MINHUNK < MAXHUNK)
MINHUNK *= 2;
}
if (_split_mem || _heapbase == NULL)
{
static int page_size = 0;
if (!page_size)
page_size = getpagesize ();
sz = (sz + page_size - 1) & -page_size;
}
q = (struct mem_chunk * )_sbrk(sz);
if (((long)q) == -1) /* can't alloc any more? */
return(NULL);
/* Note: q may be below the highest allocated chunk */
p = &_mchunk_free_list;
while (p->next != NULL && q > p->next)
p = p->next;
q->size = sz;
q->next = p->next;
q->valid = VAL_FREE;
p->next = q;
}
if (q->size > n + sizeof(struct mem_chunk))
{ /* split, leave part of free list */
q->size -= n;
q = (struct mem_chunk * )(((long) q) + q->size);
q->size = n;
q->valid = VAL_ALLOC;
}
else
{ /* just unlink it */
p->next = q->next;
q->valid = VAL_ALLOC;
}
q->next = NULL;
q++; /* hand back ptr to after chunk desc */
if(_ZeroMallocs != 0)
_bzero((void *)q, (long)(n - sizeof(struct mem_chunk)));
return((void * )q);
}
void free(param)
void *param;
{
struct mem_chunk *o, *p, *q, *s;
struct mem_chunk *r = (struct mem_chunk *) param;
extern void *_heapbase;
extern short _split_mem;
/* free(NULL) should do nothing */
if (r == 0)
return;
/* move back to uncover the mem_chunk */
r--; /* there it is! */
if (r->valid != VAL_ALLOC)
return;
r->valid = VAL_FREE;
/* stick it into free list, preserving ascending address order */
o = NULL;
p = &_mchunk_free_list;
q = _mchunk_free_list.next;
while (q != NULL && q < r)
{
o = p;
p = q;
q = q->next;
}
/* merge after if possible */
s = (struct mem_chunk * )(((long) r) + r->size);
if (q != NULL && s >= q)
{
assert(s == q);
r->size += q->size;
q = q->next;
s->size = 0;
s->next = NULL;
}
r->next = q;
/* merge before if possible, otherwise link it in */
s = (struct mem_chunk * )(((long) p) + p->size);
if (s >= r && p != &_mchunk_free_list)
/* remember: r may be below &_mchunk_free_list in memory */
{
assert(s == r);
p->size += r->size;
p->next = r->next;
r->size = 0;
r->next = NULL;
s = (struct mem_chunk * )(((long) p) + p->size);
if ((!_split_mem) && _heapbase != NULL &&
s >= (struct mem_chunk *) _heapbase &&
s < (struct mem_chunk *) ((char *)_heapbase + _stksize)) {
assert(s == (struct mem_chunk *) _heapbase);
_heapbase = (void *) p;
_stksize += p->size;
o->next = p->next; /* o is always != NULL here */
}
}
else
{
s = (struct mem_chunk * )(((long) r) + r->size);
if ((!_split_mem) && _heapbase != NULL &&
s >= (struct mem_chunk *) _heapbase &&
s < (struct mem_chunk *) ((char *)_heapbase + _stksize)) {
assert(s == (struct mem_chunk *) _heapbase);
_heapbase = (void *) r;
_stksize += r->size;
p->next = r->next;
} else p->next = r;
}
}
/*
* Set zero block after malloc flag
*/
void _malloczero(yes)
int yes;
{
_ZeroMallocs = yes;
}
/*
* tune chunk size
*/
void _mallocChunkSize (siz)
size_t siz;
{
MAXHUNK = MINHUNK = siz;
}
#ifndef __GNUC__
void * malloc(n)
size_t n;
{
return _malloc((unsigned long) n);
}
#endif